package main

import (
	"context"
	"flag"
	"fmt"
	"github.com/sirupsen/logrus"
	"github.com/spf13/viper"
	"github.com/topfreegames/pitaya/v3/pkg"
	"github.com/topfreegames/pitaya/v3/pkg/acceptor"
	"github.com/topfreegames/pitaya/v3/pkg/cluster"
	"github.com/topfreegames/pitaya/v3/pkg/component"
	"github.com/topfreegames/pitaya/v3/pkg/config"
	"github.com/topfreegames/pitaya/v3/pkg/groups"
	"github.com/topfreegames/pitaya/v3/pkg/route"
	"github.com/topfreegames/pitaya/v3/pkg/session"
	"log"
	"math/rand"
	"server/constants"
	"server/global"
	"server/modules/account"
	"server/modules/idGenerator"
	"server/modules/redisClient"
	"server/modules/user"
	"server/services/chat"
	"server/services/connector"
	"server/services/lobby"
	"server/services/myweb"
	"server/services/web"
	"time"
)

var serverType *string
var app pitaya.Pitaya

func main() {
	//这里是启动参数，启动参数写在makefile里了
	serverType = flag.String("type", "", "the server type")
	flag.Parse()
	//启动服务器
	start()
}

func start() {
	defer pitaya.Shutdown()
	logrus.SetLevel(logrus.DebugLevel)
	global.InitViper()
	//这里配置解析器，可以选择json或protobuf
	//初始化整个项目的配置
	configs := setConfig()
	configs.Set("pitaya.serializertype", 2) //配置连接类型，1是json，2是protobuf)
	cfg := config.NewConfig(configs)

	//serverCfg := configApp()
	////build := pitaya.NewBuilderWithConfigs(false, serverType, pitaya.Cluster, map[string]string{}, cfg)
	//builder := pitaya.NewDefaultBuilder(false, *serverType, pitaya.Cluster, map[string]string{}, *serverCfg)
	//app = builder.Build()
	//pitaya.DefaultApp = app
	//测试
	//str := "Connector"
	//serverType = &str

	meta := map[string]string{}
	fmt.Println("serverType", *serverType, configs.GetString("net.tcp.port"), configs.GetString("net.ws.port"))
	//这里是启动选择器，整个项目为一体化的，会根据参数的不同，启动不同的服务器
	switch *serverType {
	case "Connector": //前端服务器，为长连接服务器，用于持有所有连进来用户的长连接
		build := pitaya.NewBuilderWithConfigs(true, *serverType, pitaya.Cluster, meta, cfg)
		tcp := acceptor.NewTCPAcceptor(fmt.Sprintf(":%s", configs.GetString("net.tcp.port")))
		build.AddAcceptor(tcp)
		//build.AddAcceptor(acceptor.NewWSAcceptor(":3250"))
		ws := acceptor.NewWSAcceptor(fmt.Sprintf(":%s", configs.GetString("net.ws.port")))
		build.AddAcceptor(ws)
		build.Groups = groups.NewMemoryGroupService(build.Config.Groups.Memory)
		//build.Router.AddRoute()
		pitaya.DefaultApp = build.Build()
		session.DefaultSessionPool = build.SessionPool

		handler := connector.NewHandler(pitaya.DefaultApp)
		pitaya.Register(handler, component.WithName("Handler"))
		remote := connector.NewRemote()
		pitaya.RegisterRemote(remote, component.WithName("Remote"))

		err := pitaya.AddRoute("Connector", func(
			ctx context.Context,
			route *route.Route,
			payload []byte,
			servers map[string]*cluster.Server,
		) (*cluster.Server, error) {
			// will return the first server
			//随机获取一个服务
			serverList := make([]string, 0, len(servers))
			for id := range servers {
				serverList = append(serverList, id)
			}

			r := rand.New(rand.NewSource(time.Now().UnixNano()))
			index := r.Intn(len(serverList))
			logrus.Info("选择connect server=", servers[serverList[index]], "index= ", index)
			return servers[serverList[index]], nil

			//for k := range servers {
			//	return servers[k], nil
			//}
			//return nil, nil
		})
		if err != nil {
			fmt.Printf("error adding route %s\n", err.Error())
		}

		err = pitaya.AddRoute("Lobby", func(
			ctx context.Context,
			route *route.Route,
			payload []byte,
			servers map[string]*cluster.Server,
		) (*cluster.Server, error) {
			// will return the first server
			//随机获取一个服务
			serverList := make([]string, 0, len(servers))
			for id := range servers {
				serverList = append(serverList, id)
			}

			r := rand.New(rand.NewSource(time.Now().UnixNano()))
			index := r.Intn(len(serverList))
			logrus.Info("选择 lobby server=", servers[serverList[index]], "index= ", index)
			return servers[serverList[index]], nil

			//for k := range servers {
			//	return servers[k], nil
			//}
			//return nil, nil
		})
		if err != nil {
			fmt.Printf("error adding route %s\n", err.Error())
		}

		err = pitaya.AddRoute("Chat", func(
			ctx context.Context,
			route *route.Route,
			payload []byte,
			servers map[string]*cluster.Server,
		) (*cluster.Server, error) {
			// will return the first server
			//随机获取一个服务器
			for k := range servers {
				return servers[k], nil
			}
			return nil, nil
		})
		if err != nil {
			fmt.Printf("error adding route %s\n", err.Error())
		}

		err = pitaya.AddRoute("Web", func(ctx context.Context, route *route.Route, payload []byte, servers map[string]*cluster.Server) (*cluster.Server, error) {
			for k := range servers {
				return servers[k], nil
			}
			return nil, nil
		})

		if err != nil {
			fmt.Printf("error adding route %s\n", err.Error())
		}
		//pitaya.Configure(true, *serverType, pitaya.Cluster, meta, configs)

	case "Lobby": //大厅服务器,为长连接服务器
		pitaya.Configure(false, *serverType, pitaya.Cluster, meta, configs)
		handler := lobby.NewHandler(pitaya.DefaultApp)
		pitaya.Register(handler, component.WithName("Handler"))

	case "Web":
		pitaya.Configure(false, *serverType, pitaya.Cluster, meta, configs)
		handler := web.NewHandler()
		pitaya.Register(handler, component.WithName("Handler"))

	case "Chat":
		pitaya.Configure(false, *serverType, pitaya.Cluster, meta, configs)
		handler := chat.NewHandler(pitaya.DefaultApp)
		pitaya.Register(handler, component.WithName("Handler"))
		remote := chat.NewRemote()
		pitaya.RegisterRemote(remote, component.WithName("Remote"))
	//pitaya.AddRoute()//注册自己的路由规则
	case "MyWeb":
		pitaya.Configure(false, *serverType, pitaya.Cluster, meta, configs)
		handler := myweb.NewMyWeb()
		pitaya.Register(handler, component.WithName("Handler"))

	default:
		fmt.Printf("error serverType = %s\n", *serverType)
		return
	}
	//各服务器的公共模块
	registerPublicModule()
	registerPrivateModule()

	//启动服务器
	pitaya.Start()
}

// 配置分为两种，一种是viper对应的本地配置，一种是pitaya的系统配置
func setConfig() *viper.Viper {
	//1.从config文件中读取本地配置
	configs := readConfig()

	//2.通过pitaya设置pitaya的系统配置，pitaya的系统配置的key是已存在的，且有默认值,key可以查官网
	configs.Set("pitaya.handler.messages.compression", false)
	return configs
}

func readConfig() *viper.Viper {
	target := viper.New()
	target.SetConfigType("json")        //配置文件格式
	target.SetConfigName("development") //这里改配置名,development.json是开发模式的配置，production.json是生产模式的配置
	target.AddConfigPath("./config")    //配置文件所在的目录
	if err := target.ReadInConfig(); err != nil {
		if _, ok := err.(viper.ConfigFileNotFoundError); ok {
			log.Println("no such config file")
		} else {
			log.Println("read config error")
		}
		log.Fatal(err) // 读取配置文件失败致命错误
	}

	return target
}

func registerPublicModule() {
	//绑定etcd的模块
	//pitaya.RegisterModule(modules.NewETCDBindingStorage(pitaya.GetServer(),pitaya.sessi, pitaya.GetConfig()), "bindingsStorage")
	//注册redis
	_ = pitaya.RegisterModule(redisClient.NewManager(), constants.ModuleRedis)
}

// 各服务器，按需要，加载相应模块
func registerPrivateModule() {
	switch *serverType {
	case "Web":
		_ = pitaya.RegisterModule(idGenerator.NewManager(), constants.ModuleIdGenerator)
		_ = pitaya.RegisterModule(account.NewManager(), constants.ModuleAccount)
		_ = pitaya.RegisterModule(user.NewManager(), constants.ModuleUser)
	case "Lobby":
		_ = pitaya.RegisterModule(idGenerator.NewManager(), constants.ModuleIdGenerator)
		_ = pitaya.RegisterModule(account.NewManager(), constants.ModuleAccount)
		_ = pitaya.RegisterModule(user.NewManager(), constants.ModuleUser)
	case "MyWeb":
		_ = pitaya.RegisterModule(idGenerator.NewManager(), constants.ModuleIdGenerator)
		_ = pitaya.RegisterModule(account.NewManager(), constants.ModuleAccount)
		_ = pitaya.RegisterModule(user.NewManager(), constants.ModuleUser)
	default:
		return
	}
}
func configApp() *config.PitayaConfig {
	conf := config.NewDefaultPitayaConfig()
	conf.Buffer.Handler.LocalProcess = 15
	conf.Heartbeat.Interval = time.Duration(15 * time.Second)
	conf.Buffer.Agent.Messages = 32
	conf.Handler.Messages.Compression = false
	return conf
}
